﻿/*!
 * \file http_rep.h
 * \date 2023/05/13 16:15
 *
 * \author Yunfeng.Bo
 * Contact: Yunfeng.Bo@qq.com
 *
 * \brief   http_rep:
 *          - 实现基于 HTTP 的 client 和 server 端基于 JSON 的 response，包含错误代码处理
 *			    依赖 boost.json boost.log
 *          response_t:
 *          - 实现基于 HTTP 的 client 和 server 端基于 msgpack 的 response，包含错误代码处理
 *
 * \note
 */

#pragma once

#include "boost/json.hpp"
namespace json = boost::json;

#include "erc.hpp"
#include "serializer.hpp"

enum class rep_code {
    SUCCESS = 0,

    // 客户端错误
    NET_FAILED = 1000,   // 网络通信错误）
    TIME_OUT   = 1001,   // 网络通信超时

    // 服务端错误，除资源找不到（404）外 10000 ~ 19999
    ERR_404                 = 404,
    UNKNOWN_ERR             = 10500,
    OTHER_EXP               = 10501,
    NOT_JSON                = 10502,
    NOT_JSON_OBJ            = 10503,
    FIELD_NOT_FOUND         = 10504,
    FIELD_IS_EMPTY          = 10505,
    FIELD_TYPE_ERR          = 10506,
    FUNC_FAILED             = 10507,
    FUNC_NOT_SUPPORT        = 10508,
    HTTP_METHOD_NOT_SUPPORT = 10509,
    SERVICE_NOT_READY       = 10510,
    FUNC_REG_WRONG          = 10511,
    FUNC_PARAM_COUNT_WRONG  = 10512,

    // 存贮相关错误 （SQLite、文件系统）20000 ~ 29999
    SQLITE_ERR     = 20000,
    FILESYSTEM_ERR = 20001,

    // 设备相关错误 （device）  30000 ~ 39999
    USB_INIT_FAILED     = 30000,
    USB_DEV_LIST_FAILED = 30001,
    LIBUSB_INIT_FAILED  = 30002,   // libusb 初始化 context 时失败
    LIBUSB_OPEN_FAILED  = 30003,   // libusb 打开设备失败
    DEV_ID_NOT_EXIST    = 30004,   // 指定的设备ID不存在
    USB_TRANS_FAILED    = 30005,   // USB 数据通信失败
    SERIAL_NUM_ERROR    = 30006,   // 序列号不匹配
    PROBE_SIZE_ERROR    = 30007,   // 探头大小（行、列数）不匹配
    SAMPLE_FAILED       = 30008,   // 数据采样失败

    // 数据中心相关错误（exchange） 40000 ~ 49999
    DATA_SOURCE_IS_EMPTY = 40000,   // 注册的数据源为空
    LISTENER_IS_EMPTY    = 40001,   // 注册的监听者为空

    // 用户管理相关错误（user）50000 ~ 59999
    USER_NOT_EXIST = 50000,   // 该用户（账号）不存在
    PASSWORD_WRONG = 50001,   // 密码错误

    // 超声相关错误（cies）60000 ~ 69999
    CIES_NO_IMG_DATA = 60000,   // 没有图像数据
};

// 打包函数调用参数，辅助
template<typename Tuple, std::size_t... Index>
void package_args_impl(msgpack::serializer& sr, const Tuple& t, std::index_sequence<Index...>) {
    std::initializer_list<int>{(sr << std::get<Index>(t), 0)...};
}

// 打包函数调用参数
template<typename... Args>
void package_args(msgpack::serializer& sr, const std::tuple<Args...>& t) {
    package_args_impl(sr, t, std::index_sequence_for<Args...>{});
}

/*!
 * \class response_t
 *
 * \brief response，包含错误代码
 *         调用结果包含两个部分：
 *          - 通信结果：通信本身（发送和接收消息）是否成功，如果失败，错误代码和消息
 *          - 通信成功的情况下，调用的返回数据：可能是成功的，也可能是错误的
 *         调用的返回数据，可以是简单类型（字符串、数字等），
 *         也可以是复杂的结构，只需要支持 msgpack 打包和解包就行
 *
 * \author Yunfeng.Bo
 * \date 2023/05/24
 */
template<typename T>
class response_t : public erc {
public:
    response_t()
        : erc() {
        m_message.clear();
    }
    response_t(int code)
        : erc(code) {
        m_message.clear();
    }
    response_t(int code, std::string_view message)
        : erc(code)
        , m_message(message) {}
    response_t(int code, std::string_view message, const T& data)
        : erc(code)
        , m_message(message)
        , m_data(data) {}
    response_t(int code, std::string_view message, T* data)
        : erc(code)
        , m_message(message) {
        if (data)
            m_data = *data;
    }
    response_t(const response_t& other) = default;
    response_t(response_t&& other)
        : erc(other)
        , m_message(other.m_message)
        , m_data(other.m_data) {
        // we become the active error, the other is deactivated
        other.m_active = false;
    }

    virtual ~response_t() noexcept(false) {
        if (m_code && m_active)
            raise();
    }

    response_t& operator=(const response_t& rhs) = default;

    virtual response_t& operator=(response_t&& rhs) {
        erc::operator=(rhs);

        m_message = rhs.m_message;
        m_data    = rhs.m_data;

        return *this;
    }

    response_t& reactivate() {
        m_active = true;
        return *this;
    }

    response_t& deactivate() {
        m_active = false;
        return *this;
    }

    virtual void raise() {
        m_active = false;
        throw *this;
    }

    std::string_view message() { return m_message; }
    T&               data() { return m_data; }
    const T&         value() { return m_data; }

    void message(const std::string& m) { m_message = m; }
    void data(const T& data) { m_data = data; }
    void data(const T&& data) { m_data = std::move(data); }
    void value(const T& data) { m_data = data; }

    // 返回 HTTP status code
    inline int http_status_code() { return (m_code == 0 ? 200 : m_code); }

    // 生成 HTTP 响应 body
    std::string to_resp_body() {
        json::object obj = {{"code", http_status_code()}, {"message", m_message}, {"data", m_data}};
        return json::serialize(obj);
    }

    // 打印日志，并返回日志信息
    std::string log() {
        std::string log_text = std::format("HTTP result code:[{}] message:[{}] data: [{}]",
                                           http_status_code(),
                                           m_message,
                                           json::serialize(m_data));

        if (m_code)
            LOG_WARNING << std::format("HTTP request process failed, {}", log_text);

        return log_text;
    }

    friend msgpack::serializer& operator>>(msgpack::serializer& in, response_t<T>& d) {
        int         v;
        std::string m;

        in >> v >> m;

        d.code(v);
        d.message(m);

        // 只有调用成功，才会包含有意义的返回值
        if (d.code() == (int)rep_code::SUCCESS)
            in >> d.data();

        return in;
    }

    friend msgpack::serializer& operator<<(msgpack::serializer& out, response_t<T>& d) {
        out << d.code() << d.message() << d.data();
        return out;
    }

private:
    std::string m_message;
    T           m_data;
};

/*!
 * \class json_rep
 *
 * \brief HTTP response，值类型为 JSON 包含错误代码
 *
 * \author Yunfeng.Bo
 * \date 2023/05/13 16:26
 */
typedef response_t<json::value> json_rep;

//////////////////////////////////////////////////////////////////////////
// The SUCCESS indicator
#define HTTP_SUCCESS (json_rep(0, "success"))

// 未知错误（程序执行异常，且没有能够正确的处理）
#define HTTP_UNKNOWN_ERR (json_rep((int)rep_code::UNKNOWN_ERR, "Unknown error", nullptr))

// 其它错误（程序执行异常，且没有能够正确的处理）
#define HTTP_OTHER_EXP(what) \
    (json_rep((int)rep_code::OTHER_EXP, std::format("Other error: {}", what), nullptr))

// HTTP通信错误，错误原因由 HTTP 通信本身定义
#define HTTP_NET_ERR(code) (json_rep(code))

// 数据（请求或响应的 body），需要是 JSON 格式的字符串
#define HTTP_NOT_JSON(body) \
    (json_rep(              \
        (int)rep_code::NOT_JSON, std::format("Body not a valid JSON string '{}'", body), nullptr))

// 数据（请求或响应的 body），需要是 JSON 对象格式
#define HTTP_NOT_JSON_OBJ(body) \
    (json_rep(                  \
        (int)rep_code::NOT_JSON_OBJ, std::format("Body not a JSON object '{}'", body), nullptr))

// 请求的数据中，缺少所需的数据字段
#define HTTP_FIELD_NOT_FOUND(field)                                    \
    (json_rep((int)rep_code::FIELD_NOT_FOUND,                          \
              std::format("Request data field [{}] not found", field), \
              nullptr))

// 请求的数据中，所需的数据类型错误
#define HTTP_FIELD_TYPE_ERR(field, type)                                                 \
    (json_rep((int)rep_code::FIELD_TYPE_ERR,                                             \
              std::format("Request data field [{}] type error, need [{}]", field, type), \
              nullptr))

// 请求的数据中，数据不应为空
#define HTTP_FIELD_IS_EMPTY(field)                                    \
    (json_rep((int)rep_code::FIELD_NOT_FOUND,                         \
              std::format("Request data field [{}] is empty", field), \
              nullptr))

// 调用失败：客户端，服务端功能调用失败
#define HTTP_REMOTE_FAILED(code, msg, data) (json_rep(500, msg, data))

// 调用失败：服务端，用于响应的服务功能调用失败
#define HTTP_FUNC_FAILED(what) \
    (json_rep(                 \
        (int)rep_code::FUNC_FAILED, std::format("Request function failed: {}", what), nullptr))

// 请求指定的功能不支持
#define HTTP_FUNC_NOT_SUPPORT(reason)                                    \
    (json_rep((int)rep_code::FUNC_NOT_SUPPORT,                           \
              std::format("Request function not supported: {}", reason), \
              nullptr))

// 请求的方法不支持（GET\POST\...）
#define HTTP_METHOD_NOT_SUPPORT(method)                                      \
    (json_rep((int)rep_code::HTTP_METHOD_NOT_SUPPORT,                        \
              std::format("HTTP Request method '{}' not supported", method), \
              nullptr))

// 404，请求的 URI 不存在
#define HTTP_404(uri) \
    (json_rep((int)rep_code::ERR_404, std::format("Request uri '{}' not found", uri), nullptr))

// 请求的服务尚未准备好（后台服务未启动、服务未准备好、数据库没有准备好等等）
#define HTTP_SERVICE_NOT_READY(service_name)                               \
    (json_rep((int)rep_code::SERVICE_NOT_READY,                            \
              std::format("Request service [{}] not ready", service_name), \
              nullptr))

// 服务端方法注册错误，要求的参数在注册的方法中没有正确指定（通常由于注册时，没有正确指定所需的参数序列）
#define HTTP_FUNC_REG_WRONG \
    (json_rep((int)rep_code::FUNC_REG_WRONG, std::format("Function register error"), nullptr))

// 服务端方法注册错误，参数定义数量和实际注册的函数参数数量不同（通常由于注册时，没有正确指定所有的参数序列）
#define HTTP_FUNC_PARAM_COUNT_WRONG(arg_size, def_size)                                          \
    (json_rep(                                                                                   \
        (int)rep_code::FUNC_PARAM_COUNT_WRONG,                                                   \
        std::format("Function args size({}) not equal params define size({}), use args's size!", \
                    arg_size,                                                                    \
                    def_size),                                                                   \
        nullptr))

// SQLITE 数据操作错误
#define HTTP_SQLITE_ERR(what) \
    (json_rep((int)rep_code::SQLITE_ERR, std::format("SQLite database error: {}!", what), nullptr))

// 文件操作系统
#define HTTP_FILESYSTEM_ERR(what) \
    (json_rep((int)rep_code::FILESYSTEM_ERR, std::format("File system error: {}!", what), nullptr))

//////////////////////////////////////////////////////////////////////////
// 字符串，转换为 JSON 对象
json_rep str_to_json_object(std::string_view req_body, json::object& obj);

// 在JSON对象中，查找指定的参数
json_rep get_string(json::object& obj, std::string_view param_name, std::string& param);
json_rep get_int(json::object& obj, std::string_view param_name, int& param);
json_rep get_uint(json::object& obj, std::string_view param_name, uint64_t& param);
json_rep get_double(json::object& obj, std::string_view param_name, double& param);
json_rep get_bool(json::object& obj, std::string_view param_name, bool& param);
json_rep get_object(json::object& obj, std::string_view param_name, json::object& param);